﻿/*
 * Copyright (c) HiSilicon (Shanghai) Technologies Co., Ltd. 2023-2023. All rights reserved.
 */

#ifndef SERIALPORT_H
#define SERIALPORT_H
#include <QObject>
#include <QMutex>
#include <windows.h>
#include <QSerialPort>
#include "BurnToolCommon/MyThread.h"
#include "SerialPortWork.h"
#include "PortBase.h"

namespace SerialPortConstantValue {
    const int RX_BUFFER_SIZE = 0x2800;
}

class SerialPort : public PortBase {
    Q_OBJECT
public:
    void ClosePort() override;
    // contruction and destruction
    explicit SerialPort(QObject *parent = nullptr);
    virtual ~SerialPort();
    // port initialisation
    bool InitPort(PortBaseInitStru &serialPortInit) override;
    void InitFiled(const PortBaseInitStru &serialPortInit);
    bool SetFlowCtrl(UINT flowctrl) override;
    bool SetStopBits(UINT stopBits) override;
    bool SetDataBits(UINT dataBits) override;
    ErrorSettingCom InitPortConfigure(UINT stopbits, UINT flowctrl, UINT baud,
                               QSerialPort::Parity parity, UINT databits) override;
    void InitPortClean();
    BOOL ReInitPort() override;
    // start/stop comm watching
    BOOL StartMonitoring() override;
    void WriteToPort(const char *string, int n) override;

    bool IsThreadAlive() const override;

    void SetMsgId(UINT nMsgId);
    void SetOneTimeReadByte(DWORD mOneTimeReadByte) override;

public slots:
    void SlotHandleSerialError(QSerialPort::SerialPortError error);
    void SlotReadyRead();
protected:
    // protected memberfunctions
    static UINT CommThread(PVOID pParam);
    static void ReportBuffer(SerialPort &port);
    void WriteChar();

    QSerialPort *serialPort;
    // thread
    MyThreadClass::MyThread *readThread;
    Work::SerialPortWork *serialPortWork;
    DWORD readThreadId;
    // synchronisation objects
    CRITICAL_SECTION communicationSync;
    QMutex readMutex;
    HANDLE writeEvent;
    UINT witeThreadMsgId;
    MyThreadClass::MyThread *witeThread;
    DWORD oneTimeReadByte;

    COMMTIMEOUTS commTimeouts;
    bool isForceReadWithSleep;
    UINT forceReadTime;
    QWidget *owner;

    UINT portNr;
    char *writeBuffer;
    int writeSize;
    char rxBuffer[SerialPortConstantValue::RX_BUFFER_SIZE]; // 给10K空间，满足串口大量输出的场景. 20180720
    UINT alreadyReadByte;
    DWORD writeBufferSize;
    bool isThreadAlive;
    UINT msgId;
    bool isPortOpen;
private:
    SerialPort(const SerialPort &port)
    {
        this->writeBuffer = port.writeBuffer;
        this->writeSize = port.writeSize;
        this->readThread = new MyThreadClass::MyThread();
        this->readThreadId = port.readThreadId;
        this->owner = port.owner;
        if (memcpy_s(this->rxBuffer, SerialPortConstantValue::RX_BUFFER_SIZE, port.rxBuffer,
                     SerialPortConstantValue::RX_BUFFER_SIZE) != 0) {
            qDebug() << "memcpy error!";
        }
        this->writeEvent = port.writeEvent;
        this->writeBufferSize = port.writeBufferSize;
        this->msgId = port.msgId;
        if (memcpy_s(&(this->communicationSync), sizeof(this->communicationSync),
                     &(port.communicationSync), sizeof(port.communicationSync)) != 0) {
            qDebug() << "memcpy error!";
        }

        this->alreadyReadByte = port.alreadyReadByte;
        this->commTimeouts = port.commTimeouts;
        this->oneTimeReadByte = port.oneTimeReadByte;
        this->witeThreadMsgId = port.witeThreadMsgId;
        this->witeThread = port.witeThread;
        this->isForceReadWithSleep = port.isForceReadWithSleep;
        this->forceReadTime =  port.forceReadTime;
    };
    SerialPort &operator = (const SerialPort &port)
    {
        this->writeBuffer = port.writeBuffer;
        this->writeSize = port.writeSize;

        this->readThread = port.readThread;
        this->readThreadId = port.readThreadId;
        this->owner = port.owner;
        if (memcpy_s(this->rxBuffer, SerialPortConstantValue::RX_BUFFER_SIZE,
                     port.rxBuffer, SerialPortConstantValue::RX_BUFFER_SIZE) != 0) {
            qDebug() << "memcpy error!";
        }
        this->writeEvent = port.writeEvent;
        this->writeBufferSize = port.writeBufferSize;
        this->msgId = port.msgId;
        if (memcpy_s(&(this->communicationSync), sizeof(this->communicationSync),
                     &(port.communicationSync), sizeof(port.communicationSync)) != 0) {
            qDebug() << "memcpy error!";
        }

        this->alreadyReadByte = port.alreadyReadByte;
        this->commTimeouts = port.commTimeouts;
        this->oneTimeReadByte = port.oneTimeReadByte;
        this->witeThreadMsgId = port.witeThreadMsgId;
        this->witeThread = port.witeThread;
        this->isForceReadWithSleep = port.isForceReadWithSleep;
        this->forceReadTime =  port.forceReadTime;
        return *this;
    };
};

#endif // SERIALPORT_H
